#include <iostream>
#include<unistd.h>
#include<assert.h>
#include<sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

//封装 TCP 通信接口

#define BACKLOG 128

class TcpSocket{
  private:
    int _sockfd;
  public:
    TcpSocket():_sockfd(-1) {}
    ~TcpSocket(){}

    //1、创建套接字
    bool Socket()
    {
      _sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
      if(_sockfd<0){
        perror("socket error!\n");
        return false;
      }
      return true;
    }

    //2、绑定地址信息
    bool Bind(std::string& ip,uint16_t port)
    {
      //创建一个 ipv4 地址结构
      struct sockaddr_in addr;
      addr.sin_family=AF_INET;
      addr.sin_port=htons(port);  //主机字节序转换为网络字节序
      addr.sin_addr.s_addr=inet_addr(ip.c_str());  //转换为整型 IP 
      socklen_t len=sizeof(struct sockaddr_in);

      int ret=bind(_sockfd,(struct sockaddr*)&addr,len);
      if(ret<0){
        perror("bind error!\n");
        return false;
      }
      return true;
    }

    //开始监听
    bool Listen(int backlog = BACKLOG)
    {
      int ret=listen(_sockfd,backlog);
      if(ret<0){
        perror("listen error!\n");
        return false;
      }
      return true;
    }

    //客户端发送连接请求
    bool Connect(std::string& sip,uint16_t sport)
    {
      struct sockaddr_in addr;
      addr.sin_family=AF_INET;
      addr.sin_port=htons(sport);  //转换为网络字节序
      addr.sin_addr.s_addr=inet_addr(sip.c_str());  //转换为整型IP
      socklen_t len=sizeof(struct sockaddr_in);

      int ret=connect(_sockfd,(struct sockaddr*)&addr,len);
      if(ret<0){
        perror("connect error!\n");
          return false;
      }
      return true;
    }

    //建立新连接
    bool Accept(TcpSocket* new_sockfd,std::string* cip=NULL,uint16_t* cport=NULL)
    {
      struct sockaddr_in addr;
      socklen_t len=sizeof(struct sockaddr_in);

      int newsockfd=accept(_sockfd,(struct sockaddr*)&addr,&len);
      if(newsockfd<0){
        perror("accept error!\n");
        return false;
      }
      if(cip!=NULL)
        *cip=inet_ntoa(addr.sin_addr);  //转换为点分十进制
      if(cport!=NULL)
        *cport=ntohs(addr.sin_port);  //转化为主机字节序
      new_sockfd->_sockfd=newsockfd;       //新建连接的套接字
      return true;
    }

    //接收数据
    bool Recv(std::string* body)
    {
      char tmp[1024]={0};
      int ret=recv(_sockfd,tmp,1023,0);
      if(ret<0){
        perror("recv error!\n");
        return false;
      }
      else if(ret==0){
        std::cout<<"an orderly shutdown"<<std::endl ;  //连接关闭
        return false;
      } 
      else{
        //接收数据成功
        body->assign(tmp,ret); 
        return true;
      }
    }
    

    //发送数据
    bool Send(const std::string& body)
    {
      int ret=send(_sockfd,body.c_str(),body.size(),0);
      if(ret<0){
        perror("send error!\n");
        return false;
      }
      return true;
    }
    
    
    //关闭套接字
    bool Close()
    {
      if(_sockfd!=-1){
        close(_sockfd);
        _sockfd=-1;
      }
      return true;
    }

};



